package com.ymt.fmd.platform.web.rest;


import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;
import java.util.logging.Logger;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;

import com.ymt.fmd.appboot.prop.FmdProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

import org.apache.commons.codec.binary.Base64;

import com.alibaba.fastjson.JSONObject;
import com.ymt.fmd.platform.formdesigner.parser.impl.Json2htmlParser;
import com.ymt.fmd.platform.service.FmdService;
import com.ymt.fmd.platform.service.FormDesignerService;
import com.ymt.fmd.util.Const;


/**
 * 流程实例管理类rest类型
 * @author Johnny
 * 2013-11-2
 *
 */
@Component
@Path("/fmd")
@EnableConfigurationProperties(value = {FmdProperties.class})
public class FmdResource {
	
	private static Logger logger = Logger.getLogger(FmdResource.class.getName());

	@Autowired
	private FmdProperties fmdProperties;
	
	@Autowired
	private FmdService fmds;
	
	@Autowired
	private FormDesignerService fds;
	
	/**
	 * 请求数据
	 */
	@Context
	private HttpServletRequest request;
	
	/**
	 * save form
	 * @param param
	 * @return
	 */
	@POST
    @Path("save")
    @Produces(MediaType.APPLICATION_JSON)
	public String save(@FormParam("param")String param){
		Map<String, String> userDetail = (Map<String, String>) SecurityContextHolder.getContext().getAuthentication().getDetails();
		String tenantId = userDetail.get(Const.TENANT_ID);
		//String lang = userDetail.get(Const.LANG);
		String loginName = userDetail.get(Const.LOGINNAME);
		String displayName = userDetail.get(Const.DISPLAYNAME);
		//String lang = "zh";
		logger.finer("save param=\n"+param);
		String[] ids = fmds.saveForm(tenantId, loginName, displayName, param);
		JSONObject rtn = JSONObject.parseObject(Const.AJAX_SUCC);
		rtn.put("formid", ids[0]);
		rtn.put("versionid", ids[1]);
		return rtn.toString();
	}
	
	/**
	 * create a new form
	 * @param param
	 * @return
	 */
	@POST
    @Path("newForm")
    @Produces(MediaType.APPLICATION_JSON)
	public String newForm(@FormParam("param")String param) {
		Map<String, String> userDetail = (Map<String, String>) SecurityContextHolder.getContext().getAuthentication().getDetails();
		String loginName = userDetail.get(Const.LOGINNAME);
		String displayName = userDetail.get(Const.DISPLAYNAME);
		String tenantId = userDetail.get(Const.TENANT_ID);
		//String lang = "zh";
		logger.finer("newForm param=\n"+param);
		String[] ids = fmds.newForm(tenantId, loginName, displayName, param);
		JSONObject rtn = JSONObject.parseObject(Const.AJAX_SUCC);
		rtn.put("formid", ids[0]);
		rtn.put("versionid", ids[1]);
		return rtn.toString();
	}

	/**
	 * save form
	 * @param form
	 * @return
	 */
	@POST
    @Path("updateForm")
    @Produces(MediaType.APPLICATION_JSON)
	public String updateForm(@FormParam("form")String form){
		logger.finer("updateForm form=\n"+form);
		return fmds.updateForm(form);
	}

	/**
	 * delete form
	 * @param formid
	 * @return
	 */
	@POST
    @Path("deleteForm")
    @Produces(MediaType.APPLICATION_JSON)
	public String deleteForm(@FormParam("formid")String formid){
		logger.finer("deleteForm formid="+formid);
		String rtn = fmds.deleteForm(formid);
		return rtn;
	}

	/**
	 * query form
	 * @param form
	 * @param fromRow
	 * @param toRow
	 * @param timezoneOffset
	 * @param ordercolumns
	 * @return
	 */
	@POST
    @Path("queryForm")
    @Produces(MediaType.APPLICATION_JSON)
	public String queryForm(@FormParam("form")String form,
			@FormParam("fromRow")int fromRow,
			@FormParam("toRow")int toRow,
			@FormParam("timezoneOffset")int timezoneOffset,
			@FormParam("ordercolumns")String ordercolumns) {
		Map<String, String> userDetail = (Map<String, String>) SecurityContextHolder.getContext().getAuthentication().getDetails();
		String lang = userDetail.get(Const.LANG);
		String tenantId = userDetail.get(Const.TENANT_ID);
		logger.finer("queryForm tenantId="+tenantId);
		logger.finer("queryForm form="+form);
		logger.finer("queryForm fromRow="+fromRow);
		logger.finer("queryForm toRow="+toRow);
		logger.finer("queryForm timezoneOffset="+timezoneOffset);
		logger.finer("queryForm lang="+lang);
		logger.finer("queryForm ordercolumns="+ordercolumns);
		return fmds.queryForm(tenantId, form, fromRow, toRow, timezoneOffset, lang, ordercolumns);
	}

	/**
	 * get a version
	 * @param formid
	 * @param versionid
	 * @return
	 */
	@POST
    @Path("getVersion")
    @Produces(MediaType.APPLICATION_JSON)
	public String getVersion(@FormParam("formid")String formid, @FormParam("versionid")String versionid){
		//String lang = "zh";
		String rtn = fmds.getVersion(formid, versionid);
		logger.finer("getVersion rtn:"+rtn);
		return rtn;
	}
	
	/**
	 * delete version
	 * @param formid
	 * @param versionid
	 * @return
	 */
	@POST
    @Path("deleteVersion")
    @Produces(MediaType.APPLICATION_JSON)
	public String deleteVersion(@FormParam("formid")String formid, @FormParam("versionid")String versionid){
		logger.finer("deleteVersion formid="+formid);
		logger.finer("deleteVersion versionid="+versionid);
		String rtn = fmds.deleteVersion(formid, versionid);
		return rtn;
	}
	
	/**
	 * update version
	 * @param version
	 * @return
	 */
	@POST
    @Path("updateVersion")
    @Produces(MediaType.APPLICATION_JSON)
	public String updateVersion(@FormParam("version")String version) {
		Map<String, String> userDetail = (Map<String, String>) SecurityContextHolder.getContext().getAuthentication().getDetails();
		String loginName = userDetail.get(Const.LOGINNAME);
		String displayName = userDetail.get(Const.DISPLAYNAME);
		logger.finer("updateVersion version="+version);
		logger.finer("updateVersion loginName="+loginName);
		logger.finer("updateVersion displayName="+displayName);
		String rtn = fmds.updateVersion(version, loginName, displayName);
		return rtn;
	}

	/**
	 * @param args
	 * @param fromRow
	 * @param toRow
	 * @param timezoneOffset
	 * @param ordercolumns
	 * @return
	 */
	@POST
    @Path("queryVersion")
    @Produces(MediaType.APPLICATION_JSON)
	public String queryVersion(@FormParam("args")String args,
			@FormParam("fromRow")int fromRow,
			@FormParam("toRow")int toRow,
			@FormParam("timezoneOffset")int timezoneOffset,
			@FormParam("ordercolumns")String ordercolumns) {
		Map<String, String> userDetail = (Map<String, String>) SecurityContextHolder.getContext().getAuthentication().getDetails();
		String lang = userDetail.get(Const.LANG);
		logger.finer("queryVersion args="+args);
		logger.finer("queryVersion fromRow="+fromRow);
		logger.finer("queryVersion toRow="+toRow);
		logger.finer("queryVersion timezoneOffset="+timezoneOffset);
		logger.finer("queryVersion lang="+lang);
		logger.finer("queryVersion ordercolumns="+ordercolumns);
		return fmds.queryVersion(args, fromRow, toRow, timezoneOffset, lang, ordercolumns);
	}

	/**
	 * clone to new version
	 * @param formid
	 * @param versionid
	 * @param name
	 * @param desc
	 * @return
	 */
	@POST
    @Path("toNewVersion")
    @Produces(MediaType.APPLICATION_JSON)
	public String toNewVersion(@FormParam("formid")String formid, 
			@FormParam("versionid")String versionid,
			@FormParam("name")String name,
			@FormParam("desc")String desc) {
		Map<String, String> userDetail = (Map<String, String>) SecurityContextHolder.getContext().getAuthentication().getDetails();
		String loginName = userDetail.get(Const.LOGINNAME);
		String displayName = userDetail.get(Const.DISPLAYNAME);
		String tenantId = userDetail.get(Const.TENANT_ID);
		logger.finer("toNewVersion tenantId="+tenantId);
		logger.finer("toNewVersion formid="+formid);
		logger.finer("toNewVersion versionid="+versionid);
		logger.finer("toNewVersion name="+name);
		logger.finer("toNewVersion desc="+desc);
		logger.finer("toNewVersion loginName="+loginName);
		logger.finer("toNewVersion displayName="+displayName);
		String rtn = fmds.toNewVersion(tenantId, loginName, displayName, formid, versionid, name, desc);
		return rtn;
	}

	/**
	 * clone to new version
	 * @param formid
	 * @param versionid
	 * @param name
	 * @param desc
	 * @return
	 */
	@POST
    @Path("toNewRoVersion")
    @Produces(MediaType.APPLICATION_JSON)
	public String toNewRoVersion(@FormParam("formid")String formid, 
			@FormParam("versionid")String versionid,
			@FormParam("name")String name,
			@FormParam("desc")String desc) {
		Map<String, String> userDetail = (Map<String, String>) SecurityContextHolder.getContext().getAuthentication().getDetails();
		String loginName = userDetail.get(Const.LOGINNAME);
		String displayName = userDetail.get(Const.DISPLAYNAME);
		String tenantId = userDetail.get(Const.TENANT_ID);
		logger.finer("toNewRoVersion tenantId="+tenantId);
		logger.finer("toNewRoVersion formid="+formid);
		logger.finer("toNewRoVersion versionid="+versionid);
		logger.finer("toNewRoVersion name="+name);
		logger.finer("toNewRoVersion desc="+desc);
		logger.finer("toNewRoVersion loginName="+loginName);
		logger.finer("toNewRoVersion displayName="+displayName);
		String rtn = fmds.toNewRoVersion(tenantId, loginName, displayName, formid, versionid, name, desc);
		return rtn;
	}

	/**
	 * clone to new version
	 * @param formid
	 * @param versionid
	 * @param name
	 * @param desc
	 * @return
	 */
	@POST
    @Path("renameVersion")
    @Produces(MediaType.APPLICATION_JSON)
	public String renameVersion(@FormParam("formid")String formid, 
			@FormParam("versionid")String versionid,
			@FormParam("name")String name,
			@FormParam("desc")String desc) {
		Map<String, String> userDetail = (Map<String, String>) SecurityContextHolder.getContext().getAuthentication().getDetails();
		String loginName = userDetail.get(Const.LOGINNAME);
		String displayName = userDetail.get(Const.DISPLAYNAME);
		String tenantId = userDetail.get(Const.TENANT_ID);
		logger.finer("renameVersion tenantId="+tenantId);
		logger.finer("renameVersion formid="+formid);
		logger.finer("renameVersion versionid="+versionid);
		logger.finer("renameVersion name="+name);
		logger.finer("renameVersion desc="+desc);
		logger.finer("renameVersion loginName="+loginName);
		logger.finer("renameVersion displayName="+displayName);
		String rtn = fmds.renameVersion(tenantId, loginName, displayName, formid, versionid, name, desc);
		return rtn;
	}

	/**
	 * clone to new version
	 * @param formid
	 * @param versionid
	 * @param name
	 * @param desc
	 * @return
	 */
	@POST
    @Path("toNewForm")
    @Produces(MediaType.APPLICATION_JSON)
	public String toNewForm(@FormParam("formid")String formid, 
			@FormParam("versionid")String versionid,
			@FormParam("name")String name,
			@FormParam("desc")String desc) {
		Map<String, String> userDetail = (Map<String, String>) SecurityContextHolder.getContext().getAuthentication().getDetails();
		String loginName = userDetail.get(Const.LOGINNAME);
		String displayName = userDetail.get(Const.DISPLAYNAME);
		String tenantId = userDetail.get(Const.TENANT_ID);
		logger.finer("toNewForm tenantId="+tenantId);
		logger.finer("toNewForm formid="+formid);
		logger.finer("toNewForm versionid="+versionid);
		logger.finer("toNewForm name="+name);
		logger.finer("toNewForm desc="+desc);
		logger.finer("toNewForm loginName="+loginName);
		logger.finer("toNewForm displayName="+displayName);
		String rtn = fmds.toNewForm(tenantId, loginName, displayName, formid, versionid, name, desc);
		return rtn;
	}

	/**
	 * query history
	 * @param formid
	 * @param versionid
	 * @param args
	 * @param fromRow
	 * @param toRow
	 * @param timezoneOffset
	 * @param ordercolumns
	 * @return
	 */
	@POST
    @Path("queryHistory")
    @Produces(MediaType.APPLICATION_JSON)
	public String queryHistory(@FormParam("formid")String formid,
			@FormParam("versionid")String versionid,
			@FormParam("args")String args,
			@FormParam("fromRow")int fromRow,
			@FormParam("toRow")int toRow,
			@FormParam("timezoneOffset")int timezoneOffset,
			@FormParam("ordercolumns")String ordercolumns) {
		Map<String, String> userDetail = (Map<String, String>) SecurityContextHolder.getContext().getAuthentication().getDetails();
		String lang = userDetail.get(Const.LANG);
		logger.finer("queryHistory args="+args);
		logger.finer("queryHistory fromRow="+fromRow);
		logger.finer("queryHistory toRow="+toRow);
		logger.finer("queryHistory timezoneOffset="+timezoneOffset);
		logger.finer("queryHistory lang="+lang);
		logger.finer("queryHistory ordercolumns="+ordercolumns);
		return fmds.queryHistory(formid, versionid, args, fromRow, toRow, timezoneOffset, lang, ordercolumns);
	}

	/**
	 * get update history
	 * @param formid
	 * @param versionid
	 * @param changeno
	 * @return
	 */
	@POST
    @Path("getHistory")
    @Produces(MediaType.APPLICATION_JSON)
	public String getHistory(@FormParam("formid")String formid,
			@FormParam("versionid")String versionid,
			@FormParam("changeno")String changeno){
		logger.finer("queryHistory formid="+formid);
		logger.finer("queryHistory versionid="+versionid);
		logger.finer("queryHistory changeno="+changeno);
		return fmds.getHistory(formid, versionid, changeno);
	}
	
	/**
	 * generate form preview html
	 * @param formid
	 * @param versionid
	 * @param skin
	 * @return
	 */
	@POST
    @Path("generatePreview")
    @Produces(MediaType.APPLICATION_JSON)
	public String generatePreview(@FormParam("formid")String formid, 
			@FormParam("versionid")String versionid,
			@FormParam("skin")String skin) {
		Map<String, String> userDetail = (Map<String, String>) SecurityContextHolder.getContext().getAuthentication().getDetails();
		String lang = userDetail.get(Const.LANG);
		String realPath = request.getServletContext().getRealPath("/");
		logger.finer("generatePreview lang="+lang);
		logger.finer("generatePreview realPath="+realPath);
		logger.finer("generatePreview formid="+formid);
		logger.finer("generatePreview versionid="+versionid);
		return fds.generatePreview(formid, versionid, lang, skin, Json2htmlParser.PARSER_JS_PARSER, null, realPath);
	}
	
	/**
	 * generate form preview html for printing
	 * @param formid
	 * @param versionid
	 * @param skin
	 * @return
	 */
	@POST
    @Path("generatePrintPreview")
    @Produces(MediaType.APPLICATION_JSON)
	public String generatePrintPreview(@FormParam("formid")String formid, 
			@FormParam("versionid")String versionid,
			@FormParam("skin")String skin) {
		Map<String, String> userDetail = (Map<String, String>) SecurityContextHolder.getContext().getAuthentication().getDetails();
		String lang = userDetail.get(Const.LANG);
		String realPath = request.getServletContext().getRealPath("/");
		logger.finer("generatePrintPreview lang="+lang);
		logger.finer("generatePrintPreview realPath="+realPath);
		logger.finer("generatePrintPreview formid="+formid);
		logger.finer("generatePrintPreview versionid="+versionid);
		return fds.generatePreview(formid, versionid, lang, skin, Json2htmlParser.PARSER_JS_PRINTER, Json2htmlParser.PARSER_JS_PRINTER, realPath);
	}
	
	/**
	 * deploy version file to runtime
	 * @param formid
	 * @param versionid
	 * @param skin
	 * @return
	 */
	@POST
    @Path("deployVersion")
    @Produces(MediaType.APPLICATION_JSON)
	public String deployVersion(@FormParam("formid")String formid, 
			@FormParam("versionid")String versionid,
			@FormParam("skin")String skin,
			@FormParam("serverurl")String serverurl) {
		Map<String, String> userDetail = (Map<String, String>) SecurityContextHolder.getContext().getAuthentication().getDetails();
		String lang = userDetail.get(Const.LANG);
		String realPath = request.getServletContext().getRealPath("/");
		logger.finer("deployVersion lang="+lang);
		logger.finer("deployVersion realPath="+realPath);
		logger.finer("deployVersion formid="+formid);
		logger.finer("deployVersion versionid="+versionid);
		//logger.finer("deployVersion serverurl="+serverurl);
		serverurl = fmdProperties.getUrlFormreceiver();
		return fds.deployVersion(serverurl, formid, versionid, skin, realPath);
	}

	/**
	 * deploy all form version files to runtime
	 * @param skin
	 * @param serverurl
	 * @return
	 */
	@POST
    @Path("deployAll")
    @Produces(MediaType.APPLICATION_JSON)
	public String deployAll(@FormParam("skin")String skin,
			@FormParam("serverurl")String serverurl) {
		Map<String, String> userDetail = (Map<String, String>) SecurityContextHolder.getContext().getAuthentication().getDetails();
		String lang = userDetail.get(Const.LANG);
		String realPath = request.getServletContext().getRealPath("/");
		logger.finer("deployAll lang="+lang);
		logger.finer("deployAll realPath="+realPath);
		serverurl = fmdProperties.getUrlFormreceiver();
		logger.finer("deployVersion serverurl="+serverurl);
		return fds.deployAll(serverurl, skin, realPath);
	}

	/**
	 *
	 * @param formid
	 * @param versionid
	 * @return
	 */
	@POST
    @Path("getVersionFormData")
    @Produces(MediaType.APPLICATION_JSON)
	public String getVersionFormData(@FormParam("formid")String formid,
			@FormParam("versionid")String versionid){
		logger.finer("getVersionFormData formid="+formid);
		logger.finer("getVersionFormData versionid="+versionid);
		return fmds.getVersionFormData(formid, versionid);
	}

	/**
	 * export to a form file
	 * @param formid
	 * @param versionid
	 * @param resp
	 * @return
	 */
	@GET
    @Path("exp")
    @Produces(MediaType.APPLICATION_OCTET_STREAM)
	public String exp(@QueryParam("formid")String formid,
			@QueryParam("versionid")String versionid,
			@Context HttpServletResponse resp){
		logger.finer("exp formid="+formid);
		logger.finer("exp versionid="+versionid);
		com.alibaba.fastjson.JSONObject content = fmds.exp(formid, versionid);
		try {
			String fileName = content.getJSONObject("form").getString("formname");
			resp.setHeader("Content-Disposition", "attachment; filename="+URLEncoder.encode(fileName, "UTF-8")+"-V"+versionid+".form");
			String rtn = content.toJSONString();
			byte[] rb1 = Base64.encodeBase64(rtn.getBytes(Const.ENCODING));
			return "FMDFORM--"+new String(rb1);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * import form file
	 * @param forceNew
	 * @return
	 */
	@POST
    @Path("imp")
    @Produces(MediaType.APPLICATION_JSON)
	public String imp(@QueryParam("forceNew")boolean forceNew) {
		Map<String, String> userDetail = (Map<String, String>) SecurityContextHolder.getContext().getAuthentication().getDetails();
		String tenantId = userDetail.get(Const.TENANT_ID);
		String loginName = userDetail.get(Const.LOGINNAME);
		String displayName = userDetail.get(Const.DISPLAYNAME);
		logger.finer("imp tenantId="+tenantId);
		logger.finer("imp loginName="+loginName);
		logger.finer("imp displayName="+displayName);
		logger.finer("imp forceNew="+forceNew);
		BufferedInputStream in;
		try {
			in = new BufferedInputStream(request.getInputStream());
			BufferedReader reader = new BufferedReader(new InputStreamReader(
					in, "UTF-8"));
			StringBuffer sb = new StringBuffer();
			String str = "";
			while ((str = reader.readLine()) != null) {
				if (str != null && str.length() > 0
						&& str.startsWith("FMDFORM--")) {
					sb.append(str.substring(9));
				}
			}
			String upStr = sb.toString();
			logger.finer("imp stream:"+upStr);
			if (upStr==null || upStr.length()==0) {
				return "{\"msg\":\"invalid\"}";
			}
			byte[] rb1 = Base64.decodeBase64(upStr.getBytes(Const.ENCODING));
			String formStr = new String(rb1, Const.ENCODING);
			logger.finer("imp formStr:"+formStr);
			return fmds.imp(tenantId, loginName, displayName, forceNew, formStr);
		} catch (IOException e) {
			e.printStackTrace();
			return Const.AJAX_RESULT_FALSE;
		}
		
	}
}